﻿/*
 * BitmapBlock
 * 
 * Copyright (c) Adam Sida, asida@centrum.cz
 * 
 * All rights reserved.
 */
using System;
using System.IO;
//using System.Drawing;
//using System.Drawing.Imaging;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Petra.Gis.Geometry.Image.Tiff;



namespace Petra.Gis.Geometry.Image
{

  /// <summary>
  /// represents small rectangular portion of larger bitmap that can always fit into memory
  /// typical uncompressed size is aprox. 64kB, but can be any (no limit now)
  /// objects can:
  /// load data into existing bitmap
  /// load data into new empty bitmap
  /// extract data from existing bitmap into new bitmap
  /// </summary>
  public abstract class BitmapBlock
  {

    public enum BitmapOperationType { ExtractDataIntoNew = 0, WorkOnExisting = 1 }

    protected Int32Rect _bounds; //position of this image in destionation bitmap
    protected BlockBitmapSource _parent; //parent object that owns this child
    //protected TiffSampleFormat _tiffSampleFormat; // pixel sample format for source data
    //protected TiffPixelFormat _tifPixelFormat;
    protected BitmapSource _bitmap; //output bitmap
    protected TiffMetadata _metadata; //metadata
    protected int _index; //index of block in frame block diagram (single dimensional) 0 - N
    //protected Rectangle _areaOfInterest; //??

    #region constructors

    /// <summary>
    /// basic constructor 
    /// creates BitmapBlock from dimensions and pixelFormat only
    /// </summary>
    /// <param name="parent">owner bitmap</param>
    /// <param name="bounds">position and area of this block</param>
    /// <param name="metadata">metadata</param>
    public BitmapBlock(BlockBitmapSource parent, Int32Rect bounds, TiffMetadata metadata)
    {
      if (parent == null || bounds == null || metadata == null)
        throw new ArgumentException("null bounds or parent or metadata");

      _parent = parent;
      _bounds = bounds;
      _metadata = metadata;
      //_pixelFormat = pixelFormat;
    }




    /// <summary>
    /// creates BitmapBlock from existing bitmap
    /// </summary>
    /// <param name="parent">owner bitmap</param>
    /// <param name="sourceBmp">source bitmap to create this block from</param>
    /// <param name="srcPos">position and area of this block in source bitmap</param>
    /// <param name="metadata">metadata</param>
    public BitmapBlock(BlockBitmapSource parent, BitmapSource sourceBmp, Int32Rect srcPos, TiffMetadata metadata, BitmapOperationType oType)
      : this(parent, srcPos, metadata)
    {
      if (srcPos.X < 0 || (srcPos.X + srcPos.Width) > sourceBmp.PixelWidth ||
          srcPos.Y < 0 || (srcPos.Y + srcPos.Height) > sourceBmp.PixelHeight)
        throw new ArgumentException("invalid areaOfInterest size, larger than bitmap");

      if (oType == BitmapOperationType.WorkOnExisting)
        _bitmap = sourceBmp;
      else
        //initialize(sourceBmp, srcPos);
        _bitmap = new CroppedBitmap(sourceBmp, srcPos);

      _bounds = srcPos;
    }

    #endregion constructors


    #region public members

    /// <summary>
    /// returns 4byte aligned (32 bit) stride
    /// that is used by windows Imaging subsystem
    /// </summary>
    /// <param name="imageWidth">pixel width</param>
    /// <param name="imageBpp">bits ber pixel</param>
    /// <returns></returns>
    public static int GetStrideLenght(int imageWidth, int imageBpp)
    {
      int scanlineStride = (((imageWidth * imageBpp) + 31) / 32) * 4;
      return scanlineStride;

    }


    
    
    /// <summary>
    /// this will load data from image into block
    /// decompress if needed
    /// convert color schema if needed
    /// </summary>
    //public abstract BitmapSource GetBitmapSource(PixelFormat targetFormat);
    //public virtual void LoadData()
    //{
    //  //if bitmap created as empty initialize new
    //  if (_bitmap == null)
    //    initialize(_parentBitmap.Format);

    //}



    /// <summary>
    /// represents position and size of current BitmapBlock in destination image
    /// </summary>
    public Int32Rect Bounds
    {
      get { return _bounds; }
    }


    //public BitmapSource BitmapSource
    //{
    //  get { return _bitmap; }
    //}


    #endregion public members


    /// <summary>
    /// initializes this BitmapBlock with new empty bitmap
    /// </summary>
    protected virtual void initialize(PixelFormat pixFmt)
    {
      //_bitmap = new RenderTargetBitmap(_bounds.Width, _bounds.Height, 600, 600, pixFmt);
    }



    ///// <summary>
    ///// creates private copy of data from given bitmap
    ///// </summary>
    ///// <param name="sourceBmp">source bitmap to copy data from</param>
    ///// <param name="aoi">area of interest in this bitmap</param>
    //protected unsafe void initialize(Bitmap sourceBmp, Rectangle aoi)
    //{
    //  int pixelByteLen, rowByteLen;

    //  _bitmap = new Bitmap(aoi.Width, aoi.Height, sourceBmp.PixelFormat);
    //  BitmapData bdSrc = sourceBmp.LockBits(new Rectangle(0, 0, aoi.Width, aoi.Height), ImageLockMode.ReadOnly, sourceBmp.PixelFormat);
    //  BitmapData bdDst = sourceBmp.LockBits(new Rectangle(0, 0, aoi.Width, aoi.Height), ImageLockMode.ReadOnly, sourceBmp.PixelFormat);

    //  if((bdSrc.Stride % 8) != 0)
    //    throw new ArgumentException("unsupported PixelFormat, stride must be modulo of 8");

    //  pixelByteLen = getPixelByteSize(sourceBmp.PixelFormat);

    //  rowByteLen = pixelByteLen * aoi.Width;
    //  byte* srcBmpPtr = (byte*)bdSrc.Scan0;
    //  byte* dstBmpPtr = (byte*)bdDst.Scan0;

    //  // copy data per stride
    //  int colPos = 1;  // one based
    //  int rowPos = 0;  //zero based
    //  while (rowPos < _bitmap.Height)
    //  {
    //    *dstBmpPtr++ = *srcBmpPtr++;
    //    if (colPos++ == rowByteLen)
    //    {
    //      rowPos++;
    //      colPos = 1;
    //      srcBmpPtr += (bdSrc.Stride - rowByteLen);
    //    }
    //  }
    //  sourceBmp.UnlockBits(bdSrc);
    //  _bitmap.UnlockBits(bdDst);
    //}



  }
}
